01_1_2 データのロードとビジュアル要素への変換
テキストファイルから、座標や色を作り出す
サンプルコード:sketch01_1_2
https://i.gyazo.com/d7a0a6bf65b1e547e679639ff18ace59.png
前のサンプルで解説した基本のSketchを応用してデータをプロットします。その前に、テキスト形式で保存されたデータをロードして、座標や色の情報に変換する方法とその管理について説明します。
データ
このサンプルで使用するデータ(data.csv)は、日付、日照時間、温度、降水量をCSV形式で記録したものです。1行目はヘッダで、2行以降がデータで、合計10日間、11行のファイルになっています。ロードするデータはSketchの「data」フォルダに保存しておきます。
table:表1 データ
日付 日照時間 温度 降水量
2015/9/21 4.8 22.7 0
2015/9/22 10.7 23 0
2015/9/23 9.1 22.4 0
2015/9/24 0.9 20.4 1
2015/9/25 0 17.7 43
2015/9/26 0.6 20.5 5
2015/9/27 0.8 21.4 0
2015/9/28 9.2 23.3 0
2015/9/29 4.2 22.7 0
2015/9/30 8.9 20.9 0
code:data.csv
date,sunshine,temperature,precipitation
2015/9/21,4.8,22.7,0
2015/9/22,10.7,23,0
2015/9/23,9.1,22.4,0
2015/9/24,0.9,20.4,1
2015/9/25,0,17.7,43
2015/9/26,0.6,20.5,5
2015/9/27,0.8,21.4,0
2015/9/28,9.2,23.3,0
2015/9/29,4.2,22.7,0
2015/9/30,8.9,20.9,0
ロードしたデータを管理する「Dataクラス」
CSVからロードしたデータを格納しておくためのDataクラス(Data.pde)を定義します。今回のデータには、日付、日照時間、温度、降水量の4つのデータがあるため、Dataクラスにもこの4つのデータを格納するための可変長配列をプロパティとして用意します。
table:表2 データとDataクラスの対応関係
データ データ名 種類 可変長配列の型
日付 date 文字列 StringList
日照時間 sunshine 数値 FloatList
温度 temperature 数値 FloatList
降水量 precipitation 数値 FloatList
Data.pdeは次のようになります。
code: Data.pde
class Data{
StringList date; //日付の可変長配列
FloatList sunshine; //日照時間の可変長配列
FloatList temperature; //温度の可変長配列
FloatList precipitation; //降水量の可変長配列
Data(){
this.date = new StringList();
this.sunshine = new FloatList();
this.temperature = new FloatList();
this.precipitation = new FloatList();
}
//格納したデータの数を返すメソッド
int size(){
return date.size();
}
}
Dataクラスから、dataオブジェクトを作成しておきます。
code:sketch01_1_2.pde
Data data;
void setup() {
data = new Data();
}
データをロードする
CSV形式のデータをProcessingでロードするには、Tableオブジェクトと、TableRowオブジェクトを使います。
まずはじめにloadTable( )関数を使ってCSVファイルを読み込み、Tableオブジェクト「table」を作成します。
table = loadTable("data.csv", "header,csv");
第1引数はロードするファイル名、第2引数はオプションを指定します。"header,csv"は1行目がヘッダで、フォーマットがCSVであることを意味します。
次に、tableの各行からTableRowオブジェクト「row」を作成します。TableRowオブジェクトのgetString( )メソッドやgetFloat( )メソッドの引数にデータ名を与えて実行すると、対応するデータをそれぞれString型、float型で取り出すことができます。次の例を見てください。
TableRow row = table.getRow(0);
float n = row.getFloat("sunshine");
tableの最初の行をrowに代入し、最初の行の「日照時間」をfloat型で取得してnに代入しています。(n = 4.8)
では、実際のコードを見てみましょう。setup( )でdataオブジェクトの作成と、tableオブジェクトを介してロードしたデータをdataオブジェクトの各配列に代入する処理を行っています。
code:sketch01_1_2.pde
Table table;
Data data;
...
void setup() {
data = new Data(); //dataオブジェクトを作成
table = loadTable("data.csv", "header,csv"); //CSVファイルから、Tableオブジェクト「table」を作成
//tableの各行をTableRowオブジェクト「row」に取得し、dataオブジェクトの各配列に対応するデータをセットする。
for (TableRow row : table.rows()) {
data.date.append( row.getString("date") );
data.sunshine.append( row.getFloat("sunshine") );
data.temperature.append( row.getFloat("temperature") );
data.precipitation.append( row.getFloat("precipitation") );
}
}
ここまでで、CSVのデータをすべてdataオブジェクトに格納することがでたので、dataオブジェクトから任意のデータを取り出すことができます。例えば、
println(data.get(0).sunshine);
を実行すれば、表1で示した最初の日のデータの日照時間「4.8」がコンソールに表示されます。これらのデータを座標や色に置き換えてビジュアライズしていくのですが、このままでは扱いづらいため、各データから変換した座標と色を持つ「Vertexクラス」を新たに導入します。
座標や色を管理する「Vertexクラス」
Vertexクラス(Vertex.pde)は、データをプロットする座標(x, y, z)とその際の色を持つクラスです。データを保持するだけであれば、独立したクラスとして定義してもかまわないのですが、後のち、さまざまな処理を簡単に済ませたいため、ここではPVectorクラスを継承したクラスとして定義しています。
code:Vertex.pde
class Vertex extends PVector{
color cl;
Vertex(float x, float y, float z){
super(x,y,z);
}
void setColor(color cl){
this.cl = cl;
}
}
データからビジュアルの要素(座標や色)に変換する
ここまでで、データのロード、ロードしたデータの管理、データから変換した座標や色の保持という一連の流れに必要なパーツが出そろいました。下準備の完了です。いよいよ、ビジュアライズの本質部分である、データから座標や色への変換を行い、画面に結果を描画しましょう。
map関数
データからビジュアライズに適した数値への変換には、主にmap関数を使用します。
map関数は、ある範囲(a〜b)の範囲にある数値v1を、別の範囲(c〜d)に移した時に換算される値を返します。引数は以下のように与えます。
v2 = map(v1, a, b, c, d);
表1の温度のデータを具体例として、map関数を使ってデータを数値に置き換えてみましょう。温度が0℃から50℃までの範囲にあるとして、これをx座標の0から100までの範囲にマッピングするとします。この時、22.7℃は、x座標上のどこに位置するかは、次のように求められます。
v2 = map(22.7, 0, 50, 0, 100);
このように、データの取りうる値の範囲と、出力したい範囲(それが座標であれ、色であれ)を指定することで、データの値をビジュアライズに適した値に換算して取り出すことができます。
このサンプルコードのデータと座標・色の対応関係を整理すると、表3、表4のようになります。
table:表3 データと座標の対応関係
データ データの範囲 座標 座標の範囲
日照時間 0〜25 x座標 0〜100
温度 0〜50 y座標 0〜 -100
降水量 0〜200 z座標 0〜100
table:表4 データと色の対応関係
データ データの範囲 色 色の範囲
温度 最小値〜最大値 R 64〜255
降水量 最小値〜最大値 G 64〜255
データを変換しVertexオブジェクトに格納していく部分のコードは次のようになります。
code:sketch01_1_2.pde
ArrayList <Vertex> verts; //Vertexオブジェクトを格納する可変長配列
...
void setup(){
float x,y,z,r,g;
for(int i=0; i<data.size(); i++){
//map関数でデータを座標に変換
x = map(data.sunshine.get(i), 0, 25, 0, 100);
y = -1 *map(data.temperature.get(i), 0, 50, 0, 100);
z = map(data.precipitation.get(i), 0, 200, 0, 100);
//map関数でデータを色に変換
r = map(data.temperature.get(i), data.temperature.min(), data.temperature.max(), 64, 255);
g = map(data.precipitation.get(i), data.precipitation.min(), data.precipitation.max(), 64, 255);
//Vertexオブジェクトを配列に追加
Vertex vert = new Vertex(x, y, z);
vert.setColor( color(r, g, 255) );
verts.add(vert);
}
}
空間にプロットする
最終的なプロットは前のステップでデータを格納した配列「verts」から座標と色の情報を取り出しながら行います。
コードは次のようになります。
code:sketch01_1_2.pde
void draw(){
...
for(int i=0; i<data.size(); i++){
pushMatrix();
//プロットする位置に原点を移動
translate(verts.get(i).x, verts.get(i).y, verts.get(i).z);
//物体の色をセット
fill( red(verts.get(i).cl), green(verts.get(i).cl), blue(verts.get(i).cl), 255*plot_alpha);
box(plot_size);
popMatrix();
}
}
実行結果
https://i.gyazo.com/d7a0a6bf65b1e547e679639ff18ace59.png